using EditorExtension;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.AssetStandardProcessors;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using Yoozoo.Core.Extensions.CSharp;
using Yoozoo.Editor.Utils.AssetStandard;
using Yoozoo.Gameplay.City;
using Object = UnityEngine.Object;

namespace Gameplay.PVE
{
    public class ScenePrefabPath
    {
        public ScenePrefabPath(string path,int index)
        {
            Path = path;
            Index = index;
        }

        public string Path;
        public int Index;
    }
    
    public class SceneConfigExporter
    {
        
        private static GgameSceneConfig _sceneConfig;

        // 所有被克隆出来的预设体集合
        private static HashSet<Transform> ClonePrefabSet;

        private static HashSet<GameObject> OriginPerfabSet;

        private static string prefabRootPath;
        private static string matRootPath;
        private static string texRootPath;
        private static string meshRootPath;
        private static string meshDataRootPath;

        public static Action onStartExport;
        public static Action<PrefabData, GameObject> additionalAction;

        public static void ReimportAllTextureWithTextureStreamingOpen()
        {
            string rootName = "[Root]/Street";
            GameObject root = GameObject.Find(rootName);
            if (root == null)
            {
                EditorUtility.DisplayDialog("错误", "没有找到场景的根节点，请保证场景中有命名为 [Root] 的根节点，Active状态为True", "关闭");
                return;
            }

            // 临时关闭资源导入检测
            AssetGraphPostprocessor.Postprocessor.Enabled = false;
            
            int totalChildCount = 0;
            int currentIndex = 0;
            traverseTransformTotalChildCount(root.transform, ref totalChildCount);
            traverseTransformAndSetTextureStreaming(root.transform, ref currentIndex, totalChildCount);
            
            // 隐藏进度
            EditorUtility.ClearProgressBar();
            
            // 开启资源导入检测
            AssetGraphPostprocessor.Postprocessor.Enabled = true;
        }

        private static void traverseTransformTotalChildCount(Transform parent, ref int totalCount)
        {
            totalCount++;
            for (int i = 0; i < parent.childCount; ++i)
            {
                traverseTransformTotalChildCount(parent.GetChild(i), ref totalCount);
            }
        }

        private static void traverseTransformAndSetTextureStreaming(Transform parent, ref int currentIndex, int totalChildCount)
        {
            Renderer renderer = parent.GetComponent<Renderer>();

            currentIndex++;
            // 显示进度
            EditorUtility.DisplayProgressBar("纹理设置进度", $"正在设置{parent.name}相关纹理, ({currentIndex}/{totalChildCount})...", currentIndex/(float)totalChildCount);

            try
            {
                if (renderer)
                {
                    foreach (Material material in renderer.sharedMaterials)
                    {
                        if (!material)
                        {
                            Debug.LogError($"{renderer.transform.GetHierarchyPath()} material is null");
                            continue;
                        }

                        Shader shader = material.shader;
                        for (int i = 0; i < ShaderUtil.GetPropertyCount(shader); ++i)
                        {
                            if (ShaderUtil.GetPropertyType(shader, i) == ShaderUtil.ShaderPropertyType.TexEnv)
                            {
                                string propertyName = ShaderUtil.GetPropertyName(shader, i);
                                Texture tex = material.GetTexture(propertyName);
                                if (tex)
                                {
                                    string texPath = AssetDatabase.GetAssetPath(tex.GetInstanceID());
                                    TextureImporter textureImporter =
                                        AssetImporter.GetAtPath(texPath) as TextureImporter;
                                    if (textureImporter)
                                    {
                                        TextureImporterSettings textureImporterSettings = new TextureImporterSettings();
                                        textureImporter.ReadTextureSettings(textureImporterSettings);
                                        // Debug.LogError($"texPath: {texPath}, textureType {textureImporterSettings.textureType}");
                                        if ((textureImporterSettings.textureType == TextureImporterType.Default
                                            || textureImporterSettings.textureType == TextureImporterType.NormalMap)
                                            && textureImporterSettings.mipmapEnabled
                                            && !textureImporterSettings.streamingMipmaps)
                                        {
                                            textureImporterSettings.streamingMipmaps = true;
                                            textureImporter.SetTextureSettings(textureImporterSettings);
                                            AssetDatabase.ImportAsset(texPath);
                                        }
                                    }
                                    else
                                    {
                                        Debug.LogError($"texPath:{texPath} get TextureImporter failed");
                                    }
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Debug.LogError(e.Message);
            }

            for (int i = 0; i < parent.childCount; ++i)
            {
                traverseTransformAndSetTextureStreaming(parent.GetChild(i), ref currentIndex, totalChildCount);
            }
        }
        private static bool IsValidModification(PropertyModification modification, GameObject origin)
        {
            var result =  (modification.propertyPath == "m_ScaleInLightmap" || modification.target != null) &&
                          ( modification.target == origin.gameObject.transform ||
                            modification.target == origin.gameObject ||
                            modification.propertyPath == "m_StaticEditorFlags" ||
                            CheckMeshRenderer(modification) );
            return result;
        }
        public static bool CheckPrefabs(bool oneKey = false)
        {
            string rootName = "[Root]";
            GameObject root = GameObject.Find(rootName);
            if (root == null)
            {
                EditorUtility.DisplayDialog("错误", "没有找到场景的根节点，请保证场景中有命名为 [Root] 的根节点，Active状态为True", "关闭");
                return false;
            }
            
            // 检测迷雾名称是否有重复
            HashSet<string> airWallNames = new HashSet<string>();

            AirWallDefiner[] airWallDefiners = root.transform.GetComponentsInChildren<AirWallDefiner>();

            foreach (var airWallDefiner in airWallDefiners)
            {
                if (airWallNames.Contains(airWallDefiner.transform.name))
                {
                    EditorUtility.DisplayDialog("错误", "空气墙有名称重复，请在Console窗口查看日志", "关闭");
                    UnityEngine.Debug.LogError("空气名称重复: " + airWallDefiner.transform.name, airWallDefiner.transform);
                    return false;
                }
                else
                {
                    airWallNames.Add(airWallDefiner.transform.name);
                }
            }
            

            // 导出 Prefab
            ClonePrefabSet = new HashSet<Transform>();
            
            // 得到所有被复制出来的prefab
            Transform[] childrenTrans = root.GetComponentsInChildren<Transform>();
            foreach (var child in childrenTrans)
            {
                Transform childPrefabRoot = GetPrefabRoot(child);
                if (childPrefabRoot)
                {
                    var renderers = childPrefabRoot.GetComponentsInChildren<MeshRenderer>();
                    if (renderers!=null && renderers.Length > 0)
                    {
                        ClonePrefabSet.Add(childPrefabRoot);            // 只处理有MeshRenderer的物体
                    }
                }
            }
            
            // 得到所有原始Prefab
            OriginPerfabSet = new HashSet<GameObject>();
            Dictionary<Transform,GameObject> Clone2OriginMap = new Dictionary<Transform, GameObject>();
            
            List<GameObject> errorPrefabInst = new List<GameObject>();

            foreach (var cloned in ClonePrefabSet)
            {
                GameObject origin = PrefabUtility.GetCorrespondingObjectFromSource(cloned.gameObject);
                if (!origin)
                {
                    EditorUtility.DisplayDialog("错误", "找不到该物体的prefab"+cloned.gameObject.name, "关闭");
                }
                OriginPerfabSet.Add(origin);
                Clone2OriginMap[cloned] = origin;
                
                PropertyModification[] modifications = PrefabUtility.GetPropertyModifications(cloned.gameObject);

                
                foreach (var modification in modifications)
                {
                    if (!IsValidModification(modification, origin))
                    {
                        errorPrefabInst.Add(cloned.gameObject);
                        break;
                    }
                }

            }
            
            // 检测不规范的操作，在场景中直接更改Prefab最后没应用
            if (errorPrefabInst.Count > 0)
            {
                EditorUtility.DisplayDialog("错误", "有Prefab不符合规范，请在Console窗口查看具体信息", "关闭");
                Debug.LogError("这些物体与原Prefab的数据不一致：\n");
                for (int i = 0; i < errorPrefabInst.Count; i++)
                {
                    UnityEngine.Debug.LogError(errorPrefabInst[i].name,errorPrefabInst[i]);
                }

                return false;
            }
            else
            {
                if (!oneKey)
                {
                    EditorUtility.DisplayDialog("成功", "符合规范 ^_^", "关闭");
                }
                return true;
            }
            
        }

        public static bool CreateCfgAsset(string mapConfigName, string sceneRootPath)
        {
            onStartExport?.Invoke();
            // 配置文件
            string configPath = $"{sceneRootPath}{mapConfigName}.asset";
            _sceneConfig = AssetDatabase.LoadAssetAtPath<ScriptableObject>(configPath) as GgameSceneConfig;
            if (!_sceneConfig)
            {
                _sceneConfig = ScriptableObject.CreateInstance<GgameSceneConfig>();
                AssetDatabase.CreateAsset(_sceneConfig, configPath);
            }
            EditorUtility.SetDirty(_sceneConfig);
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
            return true;
        }

        public static bool Export(string rootName, string mapConfigName, bool renderSetting, string sceneRootPath)
        {
            AssetGraphPostprocessor.Postprocessor.Enabled = false;
            AssetGraphPostprocessor.Postprocessor.Log = false;

            onStartExport?.Invoke();
            // 配置文件
            string configPath = $"{sceneRootPath}{mapConfigName}.asset";
            _sceneConfig = AssetDatabase.LoadAssetAtPath<ScriptableObject>(configPath) as GgameSceneConfig;
            if (!_sceneConfig)
            {
                _sceneConfig = ScriptableObject.CreateInstance<GgameSceneConfig>();
                AssetDatabase.CreateAsset(_sceneConfig, configPath);
            }

            EditorUtility.DisplayProgressBar("场景数据导出", "......", 0.1f);

            GameObject root = GameObject.Find(rootName);
            bool empty = false;
            if (root == null)
            {
                if (!renderSetting)
                {
                    EditorUtility.DisplayDialog("错误", "没有找到场景的根节点，请保证场景中有命名为 [Root] 的根节点，Active状态为True", "关闭");
                    return false;
                }

                root = new GameObject("Empty");
                empty = true;
            }

            // 导出 Prefab
            ClonePrefabSet = new HashSet<Transform>();

            // 得到所有被复制出来的prefab
            Transform[] childrenTrans = root.GetComponentsInChildren<Transform>();
            foreach (var child in childrenTrans)
            {
                Transform childPrefabRoot = GetPrefabRoot(child);
                if (childPrefabRoot)
                {
                    var renderers = childPrefabRoot.GetComponentsInChildren<MeshRenderer>();
                    if (renderers != null && renderers.Length > 0)
                    {
                        ClonePrefabSet.Add(childPrefabRoot); // 只处理有MeshRenderer的物体
                    }
                }
            }

            EditorUtility.DisplayProgressBar("场景数据导出", "获取所有prefab...", 0.2f);


            // 得到所有原始Prefab
            OriginPerfabSet = new HashSet<GameObject>();
            Dictionary<Transform, GameObject> Clone2OriginMap = new Dictionary<Transform, GameObject>();

            List<GameObject> errorPrefabInst = new List<GameObject>();

            foreach (var cloned in ClonePrefabSet)
            {
                GameObject origin = PrefabUtility.GetCorrespondingObjectFromSource(cloned.gameObject);
                if (!origin)
                {
                    EditorUtility.DisplayDialog("错误", "找不到该物体的prefab" + cloned.gameObject.name, "关闭");
                    return false;
                }

                var prefabAssetType = PrefabUtility.GetPrefabAssetType(origin);
                if (prefabAssetType == PrefabAssetType.MissingAsset
                    || prefabAssetType == PrefabAssetType.Model
                    || prefabAssetType == PrefabAssetType.NotAPrefab)
                {
                    EditorUtility.DisplayDialog("错误", "该物体的prefab类型是" + prefabAssetType, "关闭");
                    return false;
                }
                
                OriginPerfabSet.Add(origin);
                Clone2OriginMap[cloned] = origin;

                PropertyModification[] modifications = PrefabUtility.GetPropertyModifications(cloned.gameObject);


                foreach (var modification in modifications)
                {
                    if (!(modification.target == null ||
                          modification.target == origin.gameObject.transform ||
                          modification.target == origin.gameObject ||
                          modification.propertyPath == "m_StaticEditorFlags" ||
                          CheckMeshRenderer(modification)))
                    {
                        errorPrefabInst.Add(cloned.gameObject);
                        break;
                    }
                }

            }

            // 检测不规范的操作，在场景中直接更改Prefab最后没应用
            if (errorPrefabInst.Count > 0)
            {
                if (EditorUtility.DisplayDialog("错误", "有物体的Prefab有更改，是否自动应用？（取消可以在Console窗口查看具体是哪些Prefab）", "确认", "取消"))
                {
                    for (int i = 0; i < errorPrefabInst.Count; i++)
                    {
                        EditorUtility.DisplayProgressBar("场景数据导出", "应用prefab..." + errorPrefabInst[i].name, 0.2f);
                        PrefabUtility.ApplyPrefabInstance(errorPrefabInst[i], InteractionMode.AutomatedAction);
                    }

                    AssetDatabase.Refresh();
                    Debug.LogError("这些物体与原Prefab的数据不一致，已被自动应用：\n");
                    for (int i = 0; i < errorPrefabInst.Count; i++)
                    {
                        UnityEngine.Debug.LogError(errorPrefabInst[i].name, errorPrefabInst[i]);
                    }
                }
                else
                {
                    Debug.LogError("这些物体与原Prefab的数据不一致：\n");
                    for (int i = 0; i < errorPrefabInst.Count; i++)
                    {
                        UnityEngine.Debug.LogError(errorPrefabInst[i].name, errorPrefabInst[i]);
                    }

                    if (empty)
                    {
                        GameObject.DestroyImmediate(root.gameObject);
                    }

                    return false;
                }
            }

            // Prefab 路径
            prefabRootPath = sceneRootPath + mapConfigName + "/Prefabs";
            ReCreateDir(prefabRootPath);
            // Material 路径
            matRootPath = sceneRootPath + mapConfigName + "/Materials";
            ReCreateDir(matRootPath);
            // Texture 路径
            texRootPath = sceneRootPath + mapConfigName + "/Texture";
            ReCreateDir(texRootPath);
            // Meshes 路径
            meshRootPath = sceneRootPath + mapConfigName + "/Meshes";
            ReCreateDir(meshRootPath);
            // MeshData 路径
            meshDataRootPath = sceneRootPath + mapConfigName + "/MeshData";
            ReCreateDir(meshDataRootPath);

            materialInfos.Clear();
            groundMaterialSet.Clear();

            if (GroundObj)
            {
                var renderers = GroundObj.GetComponentsInChildren<Renderer>();
                foreach (var renderer in renderers)
                {
                    foreach (var material in renderer.sharedMaterials)
                    {
                        if (material)
                        {
                            string assetPath = AssetDatabase.GetAssetPath(material);
                            groundMaterialSet.Add(assetPath);
                        }
                    }
                }
            }

            // 复制一份Prefab，并记录路径
            Dictionary<GameObject, ScenePrefabPath> prefab2Path = new Dictionary<GameObject, ScenePrefabPath>();
            HashSet<string> pathSet = new HashSet<string>();

            int pathIndex = 0;
            foreach (var origin in OriginPerfabSet)
            {
                string originPath = AssetDatabase.GetAssetPath(origin);
                string newPath = prefabRootPath + "/" + Path.GetFileNameWithoutExtension(originPath);

                int i = 1;
                bool t = false;
                while (pathSet.Contains(newPath))
                {
                    t = true;
                    i++;
                }

                if (t)
                {
                    // 防止重名
                    newPath += "_" + i;
                }

                newPath += ".prefab";
                pathSet.Add(newPath);

                GameObject originObj = AssetDatabase.LoadAssetAtPath<GameObject>(originPath);
                GameObject newPrefab = null;

                PrefabMeshRenderCache renderCache = null;

                newPrefab = GameObject.Instantiate(originObj);
                renderCache = newPrefab.AddComponent<PrefabMeshRenderCache>();
                MeshRenderer[] rs = newPrefab.GetComponentsInChildren<MeshRenderer>();
                renderCache.MeshRenderers = rs != null ? rs.ToList() : new List<MeshRenderer>();

                var originBinder = originObj.GetComponent<SceneObjectBinder>();
                if (originBinder)
                {
                    var binder = newPrefab.AddComponent<SceneObjectBinder>();
                    binder.ObjectType = originBinder.ObjectType;
                    binder.IsNavMesh = originBinder.IsNavMesh;
                }

                if (EditorUtility.DisplayCancelableProgressBar("场景数据导出", "复制并导出prefab..." + originObj.name,
                        0.2f + 0.5f * (pathIndex * 1.0f / OriginPerfabSet.Count)))
                {
                    return false;
                }

                EditorUtility.SetDirty(newPrefab);
                var isSuccess = SaveNewPrefab(newPrefab, newPath);
                AssetDatabase.Refresh();

                MeshCollider meshCollider = newPrefab.GetComponentInChildren<MeshCollider>(true);
                if (meshCollider)
                {
                    string fbxPath = AssetDatabase.GetAssetPath(meshCollider.sharedMesh);

                    ModelImporter mImporter = AssetImporter.GetAtPath(fbxPath) as ModelImporter;
                    if (mImporter)
                    {
                        if (!mImporter.isReadable)
                        {
                            mImporter.isReadable = true;
                            mImporter.SaveAndReimport();
                        }
                    }
                }

                AssetDatabase.Refresh();

                if (isSuccess)
                {
                    Object.DestroyImmediate(newPrefab);
                }
                else
                {
                    newPrefab.transform.SetParent(null);
                }
                prefab2Path[origin] = new ScenePrefabPath(newPath, pathIndex);
                pathIndex++;
            }

            if (IsRecalculateMaterialRenderQueue)
            {
                RecalculateMaterialRenderQueue();
            }
            else
            {
                SortMaterials();
            }

            // 将Prefab路径写入配置
            _sceneConfig.PrefabPaths = new List<string>();
            for (int i = 0; i < prefab2Path.Count; i++)
            {
                _sceneConfig.PrefabPaths.Add("");
            }

            foreach (var prefabPath in prefab2Path)
            {
                _sceneConfig.PrefabPaths[prefabPath.Value.Index] = prefabPath.Value.Path;
            }

            // 使用分块烘焙的方式，先收集所有的LightMap
            if (UseBlockBake)
            {
                InitializeLightmapData();
            }

            // 记录被复制Prefab信息
            _sceneConfig.PrefabDatas = new List<PrefabData>();
            foreach (var clonedPrefab in ClonePrefabSet)
            {
                PrefabData prefabData = new PrefabData();

                ScenePrefabPath scenePrefabPath = prefab2Path[Clone2OriginMap[clonedPrefab]];

                prefabData.resPathIndex = scenePrefabPath.Index;

                prefabData.position = clonedPrefab.position;
                prefabData.rotation = clonedPrefab.eulerAngles;
                prefabData.scale = clonedPrefab.lossyScale;

                prefabData.isStatic = false;

                // 用于处理不用模块的附加数据
                additionalAction?.Invoke(prefabData, clonedPrefab.gameObject);

                SceneObjectBinder objectBinder = clonedPrefab.gameObject.GetComponent<SceneObjectBinder>();
                if (objectBinder)
                {
                    prefabData.isStatic = objectBinder.ObjectType == SceneObjType.Static;
                }

                // 记录每个MeshRender的lightmap信息

                MeshRenderer[] renderers = clonedPrefab.gameObject.GetComponentsInChildren<MeshRenderer>();

                if (renderers != null)
                {
                    for (int i = 0; i < renderers.Length; i++)
                    {
                        MeshRendererData rendererData = new MeshRendererData();
                        MeshRenderer renderer = renderers[i];
                        if (UseBlockBake)
                        {
                            var lightmapDataLoader = renderer.GetComponent<LightMapDataLoader>();
                            if (lightmapDataLoader == null)
                            {
                                var flag = GameObjectUtility.GetStaticEditorFlags(renderer.gameObject);
                                if (flag.HasFlag(StaticEditorFlags.ContributeGI))
                                {
                                    UnityEngine.Debug.LogErrorFormat(renderer,
                                        $"{renderer.name} 上没有LightMapDataLoader");
                                }

                                continue;
                            }

                            if (lightmapDataLoader.Asset == null ||
                                lightmapDataLoader.Asset.LightMapDatas.IsEmpty())
                            {
                                UnityEngine.Debug.LogErrorFormat(renderer,
                                    $"{renderer.name} 上LightMapDataLoader的数据有错");
                                continue;
                            }

                            if (lightmapDataLoader.Asset.LightMapDatas.Length > 1)
                            {
                                UnityEngine.Debug.LogErrorFormat(renderer,
                                    $"{renderer.name} 上LightMapDataLoader的数据超过1个");
                            }

                            var meshLightmapData = lightmapDataLoader.Asset.LightMapDatas[0];
                            var customLightmapData = meshLightmapData.LightmapData;
                            rendererData.lightmapIndex = GetLightmapIndex(customLightmapData);
                            rendererData.lightmapScaleOffset = meshLightmapData.LightmapScaleOffset;
                            rendererData.scaleInLightmap = renderer.scaleInLightmap;
                            rendererData.renderIndex = i;

                            if (rendererData.lightmapIndex == -1)
                            {
                                UnityEngine.Debug.LogErrorFormat(renderer,
                                    $"{renderer.name} 上LightMapDataLoader的LightMap没有找到");
                            }
                        }
                        else
                        {
                            rendererData.lightmapIndex = renderer.lightmapIndex;
                            rendererData.lightmapScaleOffset = renderer.lightmapScaleOffset;
                            rendererData.scaleInLightmap = renderer.scaleInLightmap;
                            rendererData.renderIndex = i;
                        }

                        prefabData.MeshRendererDatas.Add(rendererData);
                    }
                }

                _sceneConfig.PrefabDatas.Add(prefabData);

                EditorUtility.DisplayProgressBar("场景数据导出", "导出prefab数据..." + clonedPrefab.name,
                    0.7f + 0.2f * (_sceneConfig.PrefabDatas.Count * 1.0f / ClonePrefabSet.Count));
            }

                // 导出全局渲染设置
            if (renderSetting)
            {
                if (!ExportRenderSetting())
                {
                    return false;
                }

                if (empty)
                {
                    Object.DestroyImmediate(root.gameObject);
                }
            }

            AssetStandardHelper.RemoveEmptyFolder(Path.GetFullPath(sceneRootPath + mapConfigName));

            EditorUtility.SetDirty(_sceneConfig);
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
            additionalAction = null;
            onStartExport = null;

            AssetGraphPostprocessor.Postprocessor.Enabled = true;
            AssetGraphPostprocessor.Postprocessor.Log = true;

            return true;
        }

        private static bool HasParent(Transform transform, string parentName)
        {
            if (transform == null)
                return false;

            while (transform != null)
            {
                if (transform.name == parentName)
                    return true;

                transform = transform.parent;
            }

            return false;
        }
        
        public static void RecalculateMaterialRenderQueue()
        {
            var guids = AssetDatabase.FindAssets("t:Material", new[] { "Assets/ResourcesAssets/Pve/Scene/" });
            var assetPaths = guids.Select(AssetDatabase.GUIDToAssetPath);
            var materialInfoList = new List<SceneConfigExporter.MaterialInfo>();
            foreach (var assetPath in assetPaths)
            {
                var material = AssetDatabase.LoadAssetAtPath<Material>(assetPath);

                StringBuilder stringBuilder = new StringBuilder();
                var keywords = new List<string>();
                foreach (var keyword in material.shaderKeywords)
                {
                    if (material.IsKeywordEnabled(keyword))
                    {
                        keywords.Add(keyword);
                    }
                }
                keywords.Sort();
                foreach (var keyword in keywords)
                {
                    stringBuilder.Append(keyword);
                    stringBuilder.Append(" ");
                }


                int renderQueue = material.renderQueue;
                if (renderQueue < (int)RenderQueue.Geometry)
                    renderQueue = (int)RenderQueue.Background;
                else if (renderQueue < (int)RenderQueue.AlphaTest)
                    renderQueue = (int)RenderQueue.Geometry;
                else if (renderQueue < (int)RenderQueue.GeometryLast)
                    renderQueue = (int)RenderQueue.Geometry;
                else if (renderQueue < (int)RenderQueue.Transparent)
                    renderQueue = (int)RenderQueue.GeometryLast;
                else if (renderQueue < (int)RenderQueue.Overlay)
                    renderQueue = (int)RenderQueue.Transparent;

                string fileName = Path.GetFileName(assetPath);
                bool isGround = fileName.StartsWith("ground_");

                materialInfoList.Add(new SceneConfigExporter.MaterialInfo
                {
                    AssetPath = assetPath,
                    Keywords = stringBuilder.ToString(),
                    RenderQueue = renderQueue,
                    ShaderName = material.shader.name,
                    NewMaterial = material,
                    IsGround = isGround
                });
            }

            materialInfoList.Sort((a, b) =>
            {
                if (a.RenderQueue != b.RenderQueue)
                    return a.RenderQueue.CompareTo(b.RenderQueue);

                if (a.IsGround != b.IsGround)
                    return a.IsGround.CompareTo(b.IsGround);

                if (a.ShaderName != b.ShaderName)
                    return string.Compare(a.ShaderName, b.ShaderName, StringComparison.Ordinal);

                if (a.Keywords != b.Keywords)
                    return string.Compare(a.Keywords, b.Keywords, StringComparison.Ordinal);

                return string.Compare(a.AssetPath, b.AssetPath, StringComparison.Ordinal);
            });

            {
                int no = 0;
                int renderQueue = 0;
                foreach (var materialInfo in materialInfoList)
                {
                    if (renderQueue != materialInfo.RenderQueue)
                    {
                        renderQueue = materialInfo.RenderQueue;
                        no = 0;
                    }

                    materialInfo.NewMaterial.renderQueue = renderQueue + no;
                    no++;

                    EditorUtility.SetDirty(materialInfo.NewMaterial);
                }

                AssetDatabase.SaveAssets();
            }
        }

        private static void SortMaterials()
        {
            var materialInfoList = materialInfos.Values.ToList();
            materialInfoList.Sort((a, b) =>
            {
                if (a.RenderQueue != b.RenderQueue)
                    return a.RenderQueue.CompareTo(b.RenderQueue);

                if (a.IsGround != b.IsGround)
                    return a.IsGround.CompareTo(b.IsGround);

                if (a.ShaderName != b.ShaderName)
                    return string.Compare(a.ShaderName, b.ShaderName, StringComparison.Ordinal);

                if (a.Keywords != b.Keywords)
                    return string.Compare(a.Keywords, b.Keywords, StringComparison.Ordinal);

                return string.Compare(a.AssetPath, b.AssetPath, StringComparison.Ordinal);
            });

            int no = 0;
            int renderQueue = 0;
            foreach (var materialInfo in materialInfoList)
            {
                if (renderQueue!= materialInfo.RenderQueue)
                {
                    renderQueue = materialInfo.RenderQueue;
                    no = 0;
                }

                materialInfo.NewMaterial.renderQueue = renderQueue + no;
                no++;

                EditorUtility.SetDirty(materialInfo.NewMaterial);
            }
        }

        /// <summary>
        /// 使用分块烘焙
        /// </summary>
        public static bool UseBlockBake = false;

        public static bool IsExportMaterial = false;

        public static bool IsCombineMesh = false;

        public static bool IsRecalculateMaterialRenderQueue = false;

        public static GameObject GroundObj = null;

        private static bool SaveNewPrefab(GameObject newPrefab, string newPath)
        {
            string assetName = Path.GetFileNameWithoutExtension(newPath);

            // 1. _jiaju下的meshrender一律shadowcaster设为off
            var roots = newPrefab.GetComponentsInChildren<Transform>(true).Where(x => x.name.Contains("_jiaju"));
            foreach (var root in roots)
            {
                var meshRenderers = root.GetComponentsInChildren<MeshRenderer>(true);
                foreach (var meshRenderer in meshRenderers)
                {
                    meshRenderer.shadowCastingMode = ShadowCastingMode.Off;
                }
            }

            // 2. 原来shadowcaster为shadow only的屋顶，可以使用一个专用材质
            var shadowOnlyMaterial =
                AssetDatabase.LoadAssetAtPath<Material>(
                    "Assets/Arts/Scene/InnerCity/Mywork/diji/Materials/neicheng_shadow_only.mat");
            var meshRenders = newPrefab.GetComponentsInChildren<MeshRenderer>(true);
            var shadowOnlyRenderers = meshRenders
                .Where(x => x.shadowCastingMode == ShadowCastingMode.ShadowsOnly);
            foreach (var shadowOnlyRenderer in shadowOnlyRenderers)
            {
                shadowOnlyRenderer.sharedMaterial = shadowOnlyMaterial;
            }

            // 3. 街道下wall, ground下的物件全部合并
            // 合并网格应该由美术完成，这里只是临时功能
            // tree下的物件不合并，树本身有LodGroup，下面合并的代码会造成LOD0和LOD1和在一起
            // 树本身面数较高，合并后会造成网格数过高
            if (IsCombineMesh)
            {
                var nodes = new[] { "wall", "ground" };
                foreach (var node in nodes)
                {
                    var n = newPrefab.transform.Find(node);
                    if (n)
                    {
                        CombineMesh(n.gameObject, $"{meshRootPath}/{assetName}_{node}_");
                    }
                }
            }

            // 统计所有的材质，按照Shader+Keywords进行排序，赋予RenderQueue
            if (IsExportMaterial)
            {
                meshRenders = newPrefab.GetComponentsInChildren<MeshRenderer>(true);
                foreach (var meshRenderer in meshRenders)
                {
                    var materials = meshRenderer.sharedMaterials;
                    for (var i = 0; i < materials.Length; i++)
                    {
                        if (materials[i] == null)
                        {
                            UnityEngine.Debug.LogError($"材质为空 {newPrefab.name}.{meshRenderer.name}.materials[{i}] == null");
                            continue;
                        }
                        materials[i] = NewMaterial(materials[i], matRootPath);
                    }

                    meshRenderer.sharedMaterials = materials;
                }
            }

            //SetMeshStreaming(newPrefab, newPath, assetName);

            //var binders = newPrefab.GetComponents<SceneObjectBinder>();
            //if (binders.IsNotEmpty())
            //{
            //    foreach (var sceneObjectBinder in binders)
            //    {
            //        Object.DestroyImmediate(sceneObjectBinder);
            //    }
            //}

            UnityEngine.Debug.Log("正在导出Prefab：" + newPrefab + " 到 " + newPath);
            try
            {
                PrefabUtility.SaveAsPrefabAsset(newPrefab, newPath);
                return true;
            }
            catch (Exception e)
            {
                UnityEngine.Debug.LogError("导出失败：" + newPrefab + " -> " + newPath + "\n" + e +  e.StackTrace);
                return false;
            }
        }

        /// <summary>
        ///  处理LOD动态加载
        /// </summary>
        /// <param name="newPrefab"></param>
        /// <param name="newPath"></param>
        /// <param name="assetName"></param>
        private static void SetMeshStreaming(GameObject newPrefab, string newPath, string assetName)
        {
            var lodGroup = newPrefab.GetComponent<LODGroup>();
            if (!lodGroup) return;

            var lods = lodGroup.GetLODs();
            if (newPrefab.name.StartsWith("rpg_road_group_"))
            {
                // 地面不使用LOD
                for (int i = 1; i < lods.Length; i++)
                {
                    var lod = lods[i];
                    foreach (var lodRenderer in lod.renderers)
                    {
                        // 这里不能删，前面收集的Renderer就失效了
                        lodRenderer.enabled = false;
                        lodRenderer.sharedMaterials = Array.Empty<Material>();
                        lodRenderer.GetComponent<MeshFilter>().sharedMesh = null;
                    }
                }
                Object.DestroyImmediate(lodGroup);
                return;
            }

            
            if (lods.Length < 2)
            {
                // 2级LOD，一般是LOD+Cull，不处理
                UnityEngine.Debug.LogWarning($"LOD数量<2: {newPath}");
                return;
            }

            if (lods.Length == 2)
            {
                var rendererLods0 = lods[0].renderers;
                var rendererLods1 = lods[1].renderers;

                var meshData = ScriptableObject.CreateInstance<MeshData>();
                string meshDataPath = $"{meshDataRootPath}/{assetName}.asset";
                List<Mesh> meshes = new List<Mesh>();

                foreach (var renderer in rendererLods0)
                {
                    if (renderer == null)
                    {
                        UnityEngine.Debug.LogError($"renderer为空: {newPath}");
                        continue;
                    }

                    var meshFilter = renderer.GetComponent<MeshFilter>();
                    if (meshFilter == null)
                    {
                        UnityEngine.Debug.LogError($"meshFilter为空: {newPath}, {renderer.name}");
                        continue;
                    }

                    var mesh = meshFilter.sharedMesh;

                    if (mesh == null)
                    {
                        UnityEngine.Debug.LogError($"mesh为空: {newPath}, {renderer.name}");
                        continue;
                    }

                    meshFilter.sharedMesh = null;

                    string newMeshAssetPath = $"{meshRootPath}/{mesh.name}.asset";
                    var isLightMapped = renderer.lightmapIndex >= 0;
                    bool useTangents = CheckIfUseTangents(renderer);
                    var newMesh = SaveMesh(mesh, newMeshAssetPath, isLightMapped, useTangents);
                    meshes.Add(newMesh);
                }

                meshData.lodMeshes = meshes.ToArray();
                AssetDatabase.CreateAsset(meshData, meshDataPath);

                foreach (var renderer in rendererLods1)
                {
                    if (renderer == null)
                    {
                        UnityEngine.Debug.LogError($"renderer为空: {newPath}");
                        continue;
                    }

                    var meshFilter = renderer.GetComponent<MeshFilter>();
                    if (meshFilter == null)
                    {
                        UnityEngine.Debug.LogError($"meshFilter为空: {newPath}, {renderer.name}");
                        continue;
                    }

                    var mesh = meshFilter.sharedMesh;

                    if (mesh == null)
                    {
                        UnityEngine.Debug.LogError($"mesh为空: {newPath}, {renderer.name}");
                        continue;
                    }


                    string newMeshAssetPath = $"{meshRootPath}/{mesh.name}.asset";
                    var isLightMapped = renderer.lightmapIndex >= 0;
                    bool useTangents = CheckIfUseTangents(renderer);
                    var newMesh = SaveMesh(mesh, newMeshAssetPath, isLightMapped, useTangents);
                    meshFilter.sharedMesh = newMesh;
                }

                var streamLodMesh = newPrefab.AddComponent<StreamLodMesh>();
                streamLodMesh.MeshDataPath = meshDataPath;
                streamLodMesh.Setup();
            }
            else if (lods.Length == 3)
            {
                var rendererLods0 = lods[0].renderers;
                var rendererLods1 = lods[1].renderers;
                var rendererLods2 = lods[2].renderers;
                
                var meshData1 = ScriptableObject.CreateInstance<MeshData>();
                var meshData2 = ScriptableObject.CreateInstance<MeshData>();
                string meshData1Path = $"{meshDataRootPath}/{assetName}_lod0.asset";
                string meshData2Path = $"{meshDataRootPath}/{assetName}_lod1.asset";
                List<Mesh> meshes = new List<Mesh>();

                foreach (var renderer in rendererLods0)
                {
                    if (renderer == null)
                    {
                        UnityEngine.Debug.LogError($"renderer为空: {newPath}");
                        continue;
                    }

                    var meshFilter = renderer.GetComponent<MeshFilter>();
                    if (meshFilter == null)
                    {
                        UnityEngine.Debug.LogError($"meshFilter为空: {newPath}, {renderer.name}");
                        continue;
                    }

                    var mesh = meshFilter.sharedMesh;

                    if (mesh == null)
                    {
                        UnityEngine.Debug.LogError($"mesh为空: {newPath}, {renderer.name}");
                        continue;
                    }

                    meshFilter.sharedMesh = null;

                    string newMeshAssetPath = $"{meshRootPath}/{mesh.name}.asset";
                    var isLightMapped = renderer.lightmapIndex >= 0;
                    bool useTangents = CheckIfUseTangents(renderer);
                    var newMesh = SaveMesh(mesh, newMeshAssetPath, isLightMapped, useTangents);
                    meshes.Add(newMesh);
                }
                meshData1.lodMeshes = meshes.ToArray();
                AssetDatabase.CreateAsset(meshData1, meshData1Path);

                meshes.Clear();
                foreach (var renderer in rendererLods1)
                {
                    if (renderer == null)
                    {
                        UnityEngine.Debug.LogError($"renderer为空: {newPath}");
                        continue;
                    }

                    var meshFilter = renderer.GetComponent<MeshFilter>();
                    if (meshFilter == null)
                    {
                        UnityEngine.Debug.LogError($"meshFilter为空: {newPath}, {renderer.name}");
                        continue;
                    }

                    var mesh = meshFilter.sharedMesh;

                    if (mesh == null)
                    {
                        UnityEngine.Debug.LogError($"mesh为空: {newPath}, {renderer.name}");
                        continue;
                    }

                    meshFilter.sharedMesh = null;

                    string newMeshAssetPath = $"{meshRootPath}/{mesh.name}.asset";
                    var isLightMapped = renderer.lightmapIndex >= 0;
                    bool useTangents = CheckIfUseTangents(renderer);
                    var newMesh = SaveMesh(mesh, newMeshAssetPath, isLightMapped, useTangents);
                    meshes.Add(newMesh);
                }
                meshData2.lodMeshes = meshes.ToArray();
                AssetDatabase.CreateAsset(meshData2, meshData2Path);

                foreach (var renderer in rendererLods2)
                {
                    if (renderer == null)
                    {
                        UnityEngine.Debug.LogError($"renderer为空: {newPath}");
                        continue;
                    }

                    var meshFilter = renderer.GetComponent<MeshFilter>();
                    if (meshFilter == null)
                    {
                        UnityEngine.Debug.LogError($"meshFilter为空: {newPath}, {renderer.name}");
                        continue;
                    }

                    var mesh = meshFilter.sharedMesh;

                    if (mesh == null)
                    {
                        UnityEngine.Debug.LogError($"mesh为空: {newPath}, {renderer.name}");
                        continue;
                    }

                    string newMeshAssetPath = $"{meshRootPath}/{mesh.name}.asset";
                    var isLightMapped = renderer.lightmapIndex >= 0;
                    bool useTangents = CheckIfUseTangents(renderer);
                    var newMesh = SaveMesh(mesh, newMeshAssetPath, isLightMapped, useTangents);
                    meshFilter.sharedMesh = newMesh;
                }

                var streamLodMesh = newPrefab.AddComponent<StreamLod3Mesh>();
                streamLodMesh.MeshData1Path = meshData1Path;
                streamLodMesh.MeshData2Path = meshData2Path;
                streamLodMesh.Setup();
            }

        }

        /// <summary>
        /// 网格中的切线是否需要
        /// </summary>
        /// <param name="renderer"></param>
        /// <returns></returns>
        static bool CheckIfUseTangents(Renderer renderer)
        {
            // 橱窗玻璃用到了切线属性
            var materials = renderer.sharedMaterials;
            foreach (var material in materials)
            {
                if (material.shader.name == "GGame/HRP/Common/PBRRT(Mixed)_Window")
                    return true;
            }

            return false;
        }

        static Mesh SaveMesh(Mesh mesh, string meshPath, bool isLightMapped, bool useTangents)
        {
            if (File.Exists(meshPath))
            {
                UnityEngine.Debug.LogWarning($"网格已存在: {meshPath}");
                var newMesh = AssetDatabase.LoadAssetAtPath<Mesh>(meshPath);
                return newMesh;
            }
            else
            {
                var newMesh = Object.Instantiate(mesh);
                newMesh.colors = null;
                if (!useTangents)
                    newMesh.tangents = null;
                newMesh.uv3 = null;
                if (!isLightMapped)
                    newMesh.uv2 = null;
                SetMeshUnreadable(newMesh);
                AssetDatabase.CreateAsset(newMesh, meshPath);
                return newMesh;
            }
        }

        static void CombineMesh(GameObject _combineTarget, string meshPath)
        {
            var meshFilters = _combineTarget.GetComponentsInChildren<MeshFilter>();
            var combineMeshInstanceDictionary = new Dictionary<Material, List<CombineInstance>>();

            foreach (var meshFilter in meshFilters)
            {

                var mesh = meshFilter.sharedMesh;
                var vertices = new List<Vector3>();
                var renderer = meshFilter.GetComponent<Renderer>();
                if (renderer.lightmapIndex >= 0)
                {
                    UnityEngine.Debug.LogError("带光照的物件不合并网格: " + _combineTarget.name + " " + renderer.name);
                    return;
                }
                var materials = renderer.sharedMaterials;
                var subMeshCount = meshFilter.sharedMesh.subMeshCount;
                mesh.GetVertices(vertices);

                for (var i = 0; i < subMeshCount; i++)
                {
                    var material = materials[i];
                    var triangles = new List<int>();
                    mesh.GetTriangles(triangles, i);

                    var newMesh = new Mesh
                    {
                        vertices = vertices.ToArray(),
                        triangles = triangles.ToArray(),
                        uv = mesh.uv,
                        normals = mesh.normals
                    };

                    if (!combineMeshInstanceDictionary.ContainsKey(material))
                    {
                        combineMeshInstanceDictionary.Add(material, new List<CombineInstance>());
                    }

                    var combineInstance = new CombineInstance
                    { transform = meshFilter.transform.localToWorldMatrix, mesh = newMesh };
                    combineMeshInstanceDictionary[material].Add(combineInstance);
                }
            }

            _combineTarget.SetActive(false);

            foreach (var kvp in combineMeshInstanceDictionary)
            {
                var newObject = new GameObject(kvp.Key.name);

                var meshRenderer = newObject.AddComponent<MeshRenderer>();
                var meshFilter = newObject.AddComponent<MeshFilter>();

                meshRenderer.sharedMaterial = kvp.Key;
                var mesh = new Mesh();
                mesh.CombineMeshes(kvp.Value.ToArray());
                Unwrapping.GenerateSecondaryUVSet(mesh);

                meshFilter.sharedMesh = mesh;
                newObject.transform.parent = _combineTarget.transform.parent;

                var path = $"{meshPath}{kvp.Key.name}.asset";
                if (File.Exists(path))
                {
                    UnityEngine.Debug.LogError($"网格已存在: {path}");
                    continue;
                }

                SetMeshUnreadable(mesh);
                AssetDatabase.CreateAsset(mesh, path);
            }
        }

        /// <summary>
        /// 合并合图过的网格，并设置光照信息
        /// </summary>
        /// <param name="meshInfos"></param>
        /// <param name="root"></param>
        /// <param name="newMeshName"></param>
        /// <returns></returns>
        static GameObject CombineMeshWithLightMap(List<MeshInfo> meshInfos, Transform root, string newMeshName)
        {
            // 参考:
            // https://www.xuanyusong.com/archives/4620
            // https://forum.unity.com/threads/combinemeshes-and-retain-lightmap-how-i-got-it-to-work.987213/
            // 实验下来不需要Awake的时候设置LightMapIndex，详见LightMapApply.Enable()注释

            var combineInstances = new List<CombineInstance>();
            Material material = null;
            int lightMapIndex = -1;
            int layer = -1;
            {
                foreach (var meshInfo in meshInfos)
                {
                    var meshRenderer = meshInfo.MeshRenderer;
                    var meshFilter = meshRenderer.GetComponent<MeshFilter>();
                    if (meshFilter == null)
                    {
                        UnityEngine.Debug.LogError($"{meshRenderer.name}没有MeshFilter");
                        continue;
                    }

                    var mesh = meshFilter.sharedMesh;
                    if (mesh == null)
                    {
                        UnityEngine.Debug.LogError($"{meshRenderer.name}的MeshFilter的网格掉了");
                        continue;
                    }

                    if (meshRenderer.sharedMaterial == null)
                    {
                        UnityEngine.Debug.LogError($"{meshRenderer.name}的材质掉了");
                        continue;
                    }

                    if (meshRenderer.sharedMaterials.Length <= meshInfo.MeshIndex)
                    {
                        UnityEngine.Debug.LogError($"{meshRenderer.name}不存在第{meshInfo.MeshIndex}个材质");
                        continue;
                    }

                    var sharedMaterial = meshRenderer.sharedMaterials[meshInfo.MeshIndex];
                    if (material == null)
                    {
                        material = sharedMaterial;
                    }
                    else if(material != sharedMaterial)
                    {
                        UnityEngine.Debug.LogError($"{meshRenderer.name}的材质不一致，应该是{material.name}，实际是{sharedMaterial.name}");
                        continue;
                    }

                    if (meshRenderer.lightmapIndex == -1)
                    {
                        if (sharedMaterial.enableInstancing)
                        {
                            // 一些小的装饰物，如植物，没有烘焙，用Instancing材质，不处理
                            continue;
                        }
                    }

                    if (lightMapIndex == -1)
                    {
                        lightMapIndex = meshRenderer.lightmapIndex;
                    }
                    else if (lightMapIndex != meshRenderer.lightmapIndex)
                    {
                        UnityEngine.Debug.LogError($"{meshRenderer.name}的LightMap不一致，应该是{lightMapIndex}，实际是{meshRenderer.lightmapIndex}");
                        continue;
                    }

                    if (layer == -1)
                    {
                        layer = meshRenderer.gameObject.layer;
                    }

                    var vertices = new List<Vector3>();
                    mesh.GetVertices(vertices);
                    var triangles = new List<int>();
                    try
                    {
                        mesh.GetTriangles(triangles, meshInfo.MeshIndex);
                    }
                    catch(Exception e)
                    {
                        Debug.LogError($"Mesh {meshInfo.MeshRenderer} {meshInfo.MeshIndex} {mesh}\n{e}");
                        continue;
                    }
                    mesh.GetTriangles(triangles, meshInfo.MeshIndex);

                    var newMesh = new Mesh
                    {
                        vertices = vertices.ToArray(),
                        triangles = triangles.ToArray(),
                        uv = mesh.uv,
                        normals = mesh.normals
                    };

                    if (lightMapIndex > -1)
                    {
                        newMesh.uv2 = mesh.uv2;
                    }

                    var matrix = root.worldToLocalMatrix;
                    var combineInstance = new CombineInstance
                    {
                        transform = matrix * meshRenderer.transform.localToWorldMatrix,
                        mesh = newMesh,
                    };

                    if (lightMapIndex > -1)
                    {
                        combineInstance.lightmapScaleOffset = meshRenderer.lightmapScaleOffset;
                    }
                    combineInstances.Add(combineInstance);
                }
            }

            if (combineInstances.IsEmpty())
                return null;

            var newObject = new GameObject(newMeshName);
            newObject.layer = layer;
            bool hasLightmapData = lightMapIndex > -1;
            if (lightMapIndex > -1)
                GameObjectUtility.SetStaticEditorFlags(newObject, StaticEditorFlags.ContributeGI);

            {
                var meshRenderer = newObject.AddComponent<MeshRenderer>();
                var meshFilter = newObject.AddComponent<MeshFilter>();

                meshRenderer.sharedMaterial = material;
                var mesh = new Mesh();
                mesh.CombineMeshes(combineInstances.ToArray(), true, true, hasLightmapData);
                if (!hasLightmapData)
                    mesh.uv2 = null;
                mesh.uv3 = null;
                mesh.Optimize();

                meshFilter.sharedMesh = mesh;

                if(hasLightmapData)
                {
                    meshRenderer.lightmapIndex = lightMapIndex;
                    meshRenderer.lightmapScaleOffset = new Vector4(1, 1, 0, 0);
                    // 已经烘焙过LightMap，不再实时产生阴影
                    meshRenderer.shadowCastingMode = ShadowCastingMode.Off;
                }
                else
                {
                    meshRenderer.shadowCastingMode = ShadowCastingMode.On;
                }

                var path = $"{meshRootPath}/{newMeshName}.asset";
                if (File.Exists(path))
                {
                    UnityEngine.Debug.LogError($"网格已存在: {path}");
                    AssetDatabase.DeleteAsset(path);
                }

                SetMeshUnreadable(mesh);

                AssetDatabase.CreateAsset(mesh, path);
            }

            return newObject;
        }

        private static void SetMeshUnreadable(Mesh mesh)
        {
            var serializedObject = new SerializedObject(mesh);
            var serializeProperty = serializedObject.FindProperty("m_IsReadable");
            serializeProperty.boolValue = false;
            serializedObject.ApplyModifiedProperties();
        }

        public class MaterialInfo
        {
            public string ShaderName;
            public Material RawMaterial;
            public Material NewMaterial;
            /// <summary>
            /// 是否是地面，地面最后画
            /// </summary>
            public bool IsGround;
            public string Keywords;
            public int RenderQueue;
            public string AssetPath;
        }

        private static Dictionary<Material, MaterialInfo> materialInfos = new Dictionary<Material, MaterialInfo>();

        private static HashSet<string> groundMaterialSet = new HashSet<string>();

        private static Material NewMaterial(Material material, string materialPath)
        {
            if (materialInfos.TryGetValue(material, out var materialInfo))
                return materialInfo.NewMaterial;

            string assetPath = AssetDatabase.GetAssetPath(material);
            bool isGround = groundMaterialSet.Contains(assetPath);
            string fileName = Path.GetFileName(assetPath);
            
            StringBuilder stringBuilder = new StringBuilder();
            var keywords = new List<string>();
            foreach (var keyword in material.shaderKeywords)
            {
                if (material.IsKeywordEnabled(keyword))
                {
                    keywords.Add(keyword);
                }
            }
            keywords.Sort();
            foreach (var keyword in keywords)
            {
                stringBuilder.Append(keyword);
                stringBuilder.Append(" ");
            }

            int renderQueue = material.renderQueue;
            if (renderQueue < (int)RenderQueue.Geometry)
                renderQueue = (int)RenderQueue.Background;
            else if (renderQueue < (int)RenderQueue.AlphaTest)
                renderQueue = (int)RenderQueue.Geometry;
            else if (renderQueue < (int)RenderQueue.GeometryLast)
                renderQueue = (int)RenderQueue.Geometry;
            else if (renderQueue < (int)RenderQueue.Transparent)
                renderQueue = (int)RenderQueue.GeometryLast;
            else if (renderQueue < (int)RenderQueue.Overlay)
                renderQueue = (int)RenderQueue.Transparent;
            
            var path = $"{materialPath}/{fileName}";
            if (isGround)
                path = $"{materialPath}/ground_{fileName}";

            if (File.Exists(path))
            {
                int no = 2;
                string newPath = path.Replace(".mat", $"_{no:D2}.mat");
                while (File.Exists(newPath))
                {
                    no++;
                    newPath = path.Replace(".mat", $"_{no:D2}.mat");
                }

                path = newPath;
            }

            AssetDatabase.CreateAsset(new Material(material), path);
            var newMaterial = AssetDatabase.LoadAssetAtPath<Material>(path);
            materialInfo = new MaterialInfo
            {
                ShaderName = material.shader.name,
                RawMaterial = material,
                NewMaterial = newMaterial,
                Keywords = stringBuilder.ToString(),
                RenderQueue = renderQueue,
                AssetPath = path,
                IsGround = isGround
            };

            materialInfos[material] = materialInfo;
            return newMaterial;
        }

        private static bool ExportRenderSetting()
        {
            SceneRenderData renderData = _sceneConfig.RenderData;
            renderData.useBlockBake = UseBlockBake;
            
            //ReCreateDir(prefabRootPath + "/Setting");
            //renderData.settingPath
            
            // lightMap
            List<string> lightMapPaths = new List<string>();
            for (int i = 0; i < LightmapSettings.lightmaps.Length; i++)
            {
                string mapPath = texRootPath + string.Format("/Lightmap-{0}_comp_light.tga",i);
                EditorUtility.DisplayProgressBar("场景数据导出", "导出lightMap..." + mapPath, 0.9f + 0.1f*(i*1.0f/LightmapSettings.lightmaps.Length));

                var path = AssetDatabase.GetAssetPath(LightmapSettings.lightmaps[i].lightmapColor);
                AssetDatabase.CopyAsset(path, mapPath);
                AssetDatabase.Refresh();
                lightMapPaths.Add(mapPath);
            }
            renderData.lightMapColorPath = new List<string>();
            renderData.lightMapColorPath.AddRange(lightMapPaths);
            
            List<string> lightMapDirPaths = new List<string>();
            for (int i = 0; i < LightmapSettings.lightmaps.Length; i++)
            {
                string mapPath = texRootPath + string.Format("/Lightmap-{0}_comp_dir.png",i);
                var path = AssetDatabase.GetAssetPath(LightmapSettings.lightmaps[i].lightmapDir);
                AssetDatabase.CopyAsset(path, mapPath);
                AssetDatabase.Refresh();
                lightMapDirPaths.Add(mapPath);
            }
            renderData.lightMapDirPath = new List<string>();
            renderData.lightMapDirPath.AddRange(lightMapDirPaths);

            // fog 
            renderData.isFog = RenderSettings.fog;
            renderData.fogColor = RenderSettings.fogColor;
            renderData.fogStart = RenderSettings.fogStartDistance;
            renderData.fogEnd = RenderSettings.fogEndDistance;
            renderData.fogMode = RenderSettings.fogMode;
            
            // skyBox
            if (RenderSettings.skybox!=null) {
                var skyBoxMat = Material.Instantiate(RenderSettings.skybox); 
                var skyBoxMatPath = matRootPath + "/mat_SkyBox.mat";
                AssetDatabase.CreateAsset(skyBoxMat, skyBoxMatPath);
                AssetDatabase.Refresh(); 
                renderData.skyBoxMaterialPath = skyBoxMatPath;
            }
            
            // 反射探针
            string renderPath = prefabRootPath + "/RenderSetting";
            Directory.CreateDirectory(Application.dataPath.Replace("Assets", "") + renderPath);
            GameObject fathReflection = GameObject.Find("Reflection_Bake");
            if (fathReflection)
            {
                foreach(ReflectionProbe child in fathReflection.GetComponentsInChildren<ReflectionProbe>(true)){
                    child.mode=ReflectionProbeMode.Custom;
                    child.customBakedTexture=child.bakedTexture;
                }

                PrefabUtility.SaveAsPrefabAsset(fathReflection.gameObject, renderPath +"/Reflection_Bake.prefab");
                foreach(ReflectionProbe child in fathReflection.GetComponentsInChildren<ReflectionProbe>(true)){
                    child.mode=ReflectionProbeMode.Baked;
                }

                renderData.reflectionProbePath = renderPath + "/Reflection_Bake.prefab";
            }
            
            // other
            renderData.ambientColor = RenderSettings.ambientLight;
            renderData.ambientMode = RenderSettings.ambientMode;
            renderData.reflectionMode = RenderSettings.defaultReflectionMode;

            // Shadow Cache
            var shadowCache = Object.FindObjectOfType<GShadowCache>();
            if (shadowCache && shadowCache.savedShadowCacheDepthTex)
            {
                string mapPath = texRootPath + "/tex_shadowCacheDepth.tga";
                EditorUtility.DisplayProgressBar("场景数据导出", "导出ShadowCache..." + mapPath, 0.99f);

                var path = AssetDatabase.GetAssetPath(shadowCache.savedShadowCacheDepthTex);
                AssetDatabase.CopyAsset(path, mapPath);
                AssetDatabase.Refresh();

                renderData.shadowCacheDepthTexturePath = mapPath;
                renderData.shadowCacheMatrix = shadowCache.shadowCacheMatrix;
                renderData.shadowCacheTexelSize = shadowCache.shadowCacheTexelSize;
            }
            
            // 废弃
            // var lightingDataPath = AssetDatabase.GetAssetPath(Lightmapping.lightingDataAsset);
            // var reflectProbePath = lightingDataPath.Replace("LightingData.asset", "ReflectionProbe-0.exr");
            // var reflectProbeNewPath = texRootPath + "/ReflectionProbe-0.exr";
            // renderData.reflectionProbePath = reflectProbeNewPath;
            // AssetDatabase.CopyAsset(reflectProbePath, reflectProbeNewPath);
            AssetDatabase.Refresh();
            
            return true;
        }
        


        #region Helper

        private static bool CheckMeshRenderer(PropertyModification modification)
        {
           
            var result=  modification.target is MeshRenderer && 
                   (!modification.propertyPath.Contains("m_Materials") ||
                    ((MeshRenderer) modification.target).sharedMaterials.Contains((Material) modification.objectReference));
            
            return true;   
        }
        
        private static Transform GetPrefabRoot(Transform trans)
        {
            GameObject prefab = PrefabUtility.GetCorrespondingObjectFromSource(trans.gameObject);
            if (!prefab)
            {
                return null;
            }

            Transform t = null;
            while (trans)
            {
                GameObject obj = PrefabUtility.GetCorrespondingObjectFromSource(trans.gameObject);
                if (obj)
                {
                    t = trans;
                }
                trans = trans.parent;
            }

            return t;
        }
        
        private static void ReCreateDir(string path)
        {
            DeleteDir(Application.dataPath.Replace("Assets", "") + path, true);
            Directory.CreateDirectory(Application.dataPath.Replace("Assets", "") + path);
        }
        
        private static void DeleteDir(string path, bool deleteOwner)
        {
            if (path.Trim() == "" || !Directory.Exists(path)) return;
            DirectoryInfo dirInfo = new DirectoryInfo(path);
            FileInfo[] fileInfos = dirInfo.GetFiles();
            if (fileInfos != null && fileInfos.Length > 0)
            {
                foreach (FileInfo fileInfo in fileInfos)
                {
                    File.Delete(fileInfo.FullName);
                }
            }
            DirectoryInfo[] dirInfos = dirInfo.GetDirectories();
            if (dirInfos != null && dirInfos.Length > 0)
            {
                foreach (DirectoryInfo childDirInfo in dirInfos)
                {
                    DeleteDir(childDirInfo.FullName, true);
                }
            }
            if (deleteOwner)
            {
                Directory.Delete(dirInfo.FullName, true);
            }
        }

        #endregion

        #region 分块烘焙

        private static List<LightmapData> lightmapDataList = new List<LightmapData>();

        private static void InitializeLightmapData()
        {
            lightmapDataList.Clear();

            foreach (var clonedPrefab in ClonePrefabSet)
            {
                var loaders = clonedPrefab.GetComponentsInChildren<LightMapDataLoader>(true);
                foreach (var lightMapDataLoader in loaders)
                {
                    if (lightMapDataLoader.Asset && lightMapDataLoader.Asset.LightMapDatas.IsNotEmpty())
                    {
                        foreach (var assetLightMapData in lightMapDataLoader.Asset.LightMapDatas)
                        {
                            bool isContains = false;
                            foreach (var lightmapData in lightmapDataList)
                            {
                                if (assetLightMapData.LightmapData.IsA(lightmapData))
                                {
                                    isContains = true;
                                    break;
                                }
                            }

                            if (!isContains)
                            {
                                var lightmapData = assetLightMapData.LightmapData.GetLightmapData();
                                lightmapDataList.Add(lightmapData);
                            }
                        }
                    }
                }
            }

            SaveLightmap();
        }

        private static int GetLightmapIndex(CustomLightmapData customLightmapData)
        {
            for (var i = 0; i < lightmapDataList.Count; i++)
            {
                var lightmapData = lightmapDataList[i];
                if (customLightmapData.IsA(lightmapData))
                {
                    return i;
                }
            }

            return -1;
        }

        private static void SaveLightmap()
        {
            if (lightmapDataList.IsEmpty())
            {
                return;
            }
            LightmapSettings.lightmaps = lightmapDataList.ToArray();
        }
        #endregion

        class MeshInfo
        {
            public MeshRenderer MeshRenderer;
            public int MeshIndex;
        }

        [MenuItem("GTATools/开放世界/修正预制体")]
        private static void FixPrefabs()
        {
            var gameObjects = Selection.gameObjects;
            if (gameObjects.IsEmpty())
            {
                EditorUtility.DisplayDialog("提示", "至少选中1个场景中的预制体", "确定");
                return;
            }

            bool isDirty = false;
            foreach (var gameObject in gameObjects)
            {
                var prefabAssetType = PrefabUtility.GetPrefabAssetType(gameObject);
                if (prefabAssetType != PrefabAssetType.Regular && prefabAssetType != PrefabAssetType.Variant)
                {
                    continue;
                }

                if (!PrefabUtility.IsOutermostPrefabInstanceRoot(gameObject))
                {
                    continue;
                }

                string assetPath = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(gameObject);
                var origin = AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);

                var modifications = PrefabUtility.GetPropertyModifications(gameObject);
                var newModifications = new List<PropertyModification>();

                foreach (var modification in modifications)
                {
                    if (modification.target == null ||
                        modification.target == origin.transform ||
                        modification.target == origin ||
                        modification.propertyPath == "m_StaticEditorFlags" ||
                        CheckMeshRenderer(modification))
                    {
                        newModifications.Add(modification);
                    }
                }

                if (modifications.Length == newModifications.Count)
                {
                    continue;
                }

                PrefabUtility.SetPropertyModifications(gameObject, newModifications.ToArray());
                isDirty = true;
            }

            if (isDirty)
                EditorSceneManager.MarkSceneDirty(SceneManager.GetActiveScene());
        }
    }
}
